package dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.LinkedList;
import java.util.List;
import blogLib.itf.IUsuario;
import java.sql.Types;
import model.Usuario;

/**
 * Classe de tradução de dados de objeto para modelo relacional
 * @author Alan Alves Oliveira
 */
public class UsuarioDAO extends ConexaoBD {
    private Connection conn;

    /**
     * Construtor que gera uma conexão
     * @throws ClassNotFoundException
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws SQLException
     */
    public UsuarioDAO(String caminho, String nomeBD, String usuario, String senha) throws ClassNotFoundException, InstantiationException, IllegalAccessException, SQLException {
        this.conn = getConexao(caminho, nomeBD, usuario, senha);
    }

    /**
     * Construtor que recebe uma conexão
     * @param conn Conexão com banco de dados
     */
    public UsuarioDAO(Connection conn) {
        this.conn = conn;
    }

    /**
     * Retorna um usuário pelo login
     * @param login Login do usuário a ser retornado
     * @return Objeto IUsuario. Se o usuário não existir, retorna null
     * @throws SQLException
     */
    public IUsuario getUsuario(String login) throws SQLException {
        ResultSet rs = null;
        PreparedStatement pst = null;
        IUsuario u = null;
        try {
            pst = conn.prepareStatement("SELECT * FROM usuario WHERE Login = ?");
            pst.setString(1, login);
            rs = pst.executeQuery();
            if (rs.next())
                u = getUsuarioFromSQL(rs);
            return u;
        } catch (SQLException e) {
            throw new SQLException(e.getMessage());
        } finally {
            pst.close();
            rs.close();
        }
    }

    /**
     * Retorna uma lista de usuários
     * @return Objeto List com uma lista de usuários
     * @throws SQLException
     */
    public List<IUsuario> getListaUsuario() throws SQLException {
        List<IUsuario> usuarios = new LinkedList<IUsuario>();
        ResultSet rs = null;
        Statement st = null;
        try {
            st = conn.createStatement();
            rs = st.executeQuery("SELECT * FROM usuario");
            while (rs.next())
               usuarios.add(getUsuarioFromSQL(rs));
            return usuarios;
        } catch (SQLException e) {
            throw new SQLException(e.getMessage());
        } finally {
            st.close();
            rs.close();
        }
    }

    /**
     * Retorna uma lista de usuários filtrando pelo nome ou parte dele
     * @param parteNome Nome ou parte do nome do usuário
     * @return Objeto List com uma lista de usuários
     * @throws SQLException
     */
    public List<IUsuario> getListaUsuario(String parteNome) throws SQLException {
        List<IUsuario> usuarios = new LinkedList<IUsuario>();
        ResultSet rs = null;
        PreparedStatement pst = null;
        try {
            String sql = "SELECT * FROM usuario WHERE Nome LIKE ?";
            pst = conn.prepareStatement(sql);
            pst.setString(1, parteNome + "%");
            rs = pst.executeQuery();
            while (rs.next())
                usuarios.add(getUsuarioFromSQL(rs));
            return usuarios;
        } catch (SQLException e) {
            throw new SQLException(e.getMessage());
        } finally {
            pst.close();
            rs.close();
        }
    }

    /**
     * Faz a persistência de um usuário no banco de dados
     * @param u Objeto IUsuario
     * @throws SQLException
     */
    public void incluiUsuario(IUsuario u) throws SQLException {
        PreparedStatement pst = null;
        try {
            pst = conn.prepareStatement("INSERT INTO usuario VALUES (?, ?, ?)");
            UtilidadeSQL.verificaNulo(u.getLogin(), Types.VARCHAR, pst, 1);
            UtilidadeSQL.verificaNulo(u.getNome(), Types.VARCHAR, pst, 2);
            UtilidadeSQL.verificaNulo(u.getSenha(), Types.VARCHAR, pst, 3);
            pst.execute();
        } catch (SQLException e) {
            throw new SQLException(e.getMessage());
        } finally {
            pst.close();
        }

    }

    /**
     * Altera um usuário persistido. Somente os atributos nome e senha podem ser alterados
     * por este método
     * @param u Objeto IUsuario
     * @throws SQLException
     */
    public void alteraUsuario(IUsuario u) throws SQLException {
        PreparedStatement pst = null;
        try {
            pst = conn.prepareStatement("UPDATE usuario SET" +
                " Nome = ?," +
                " Senha = ?" +
                " WHERE Login = ?");
            UtilidadeSQL.verificaNulo(u.getNome(), Types.VARCHAR, pst, 1);
            UtilidadeSQL.verificaNulo(u.getSenha(), Types.VARCHAR, pst, 2);
            pst.setString(3, u.getLogin());
            pst.execute();
        } catch (SQLException e) {
            throw new SQLException(e.getMessage());
        } finally {
            pst.close();
        }
    }

    /**
     * Exclui um usuário persistido
     * @param login Login do usuário
     * @return Usuário excluído. Se o usuário não existir, retorna null
     * @throws SQLException
     */
    public IUsuario excluiUsuario(String login) throws SQLException {
        PreparedStatement pst = null;
        try {
            IUsuario u = this.getUsuario(login);
            pst = conn.prepareStatement("DELETE FROM usuario WHERE Login = ?");
            pst.setString(1, login);
            pst.execute();
            return u;
        } catch (SQLException e) {
            throw new SQLException(e.getMessage());
        } finally {
            pst.close();
        }
    }

    /**
     * Instancia um objeto IUsuarioComum a partir do resultado em um ResultSet
     * @param rs Objeto ResultSet que contém os dados do usuário
     * @return Objeto IUsuarioComum
     * @throws SQLException
     */
    private IUsuario getUsuarioFromSQL(ResultSet rs) throws SQLException {
        IUsuario u = new Usuario();
        u.setLogin(rs.getString("Login"));
        u.setNome(rs.getString("Nome"));
        u.setSenha(rs.getString("Senha"));
        return u;
    }

}